import _ from "lodash";
import moment from "moment";
import ora, { Ora } from "ora";
import { Nullable, Undef } from "../typings/index.js";

export class Status {
    private static instance: Status;
    public static get Instance(): Status {
        if(!Status.instance) {
            Status.instance = new Status();
        }
        return Status.instance;
    }

    private spinner: Nullable<Ora> = null;

    private taskName = '';
    private stage: Undef<string>;
    private crtCnt = 0;
    private total = 0;
    private startAt = 0;

    private errors: string[] = [];

    public startTask(name: string, total: number): void {
        this.end();
        this.taskName = name;
        this.total = total;
        this.startAt = _.now();
        this.reset();
    }

    public reset(stage?: string): void {
        this.crtCnt = 0;
        this.stage = stage;
        this.spinner = ora(this.title).start(`${moment().format('HH:mm:ss')}  ${this.title} (${this.crtCnt}/${this.total})`);
    }

    public update(info: string): void {
        this.crtCnt++;
        if (this.spinner != null) {
            this.spinner.text = `${moment().format('HH:mm:ss')}  ${this.title} (${this.crtCnt}/${this.total}): ${info}`;
        }
    }

    public end(): void {
        if (this.spinner != null) {
            this.spinner.succeed();
            this.spinner = null;
        }
        this.taskName = '';
    }

    private get title(): string {
        let title = this.taskName;
        if (this.stage != null) title += ' ' + this.stage;
        return title;
    }

    public emptyErrors(): void {
        this.errors.length = 0;
    }

    public collect(error: string): void {
        if (this.spinner != null) {
            this.errors.push(`[${this.title}] ${error}`);
        } else {
            console.error(error);
        }
    }

    public dumpErrors(): void {
        console.error('--------------------ERRORS--------------------');
        for (const e of this.errors) {
            console.error(e);
        }
    }
}
